Mise à jour le 13/11/2021
DebugDoctrineRepositoryTrait

DebugDoctrineRepositoryTrait


1. Contexte

Doctrine2 utilise une classe Query qui possède deux méthodes, getDQL et getSQL.
Malheureusement, aucune de ces deux méthodes ne permet de savoir quelle est la requête SQL finalement executée par le serveur.

Ce snippet permet d'évaluer ce que serait cette requête.

2. Dépendances :

- Doctrine ORM (https://packagist.org/packages/doctrine/orm) pour la classe Query.
- Symfony VarDumper (https://packagist.org/packages/symfony/var-dumper) pour la méthode dump() (pensez à décommenter le code).

3. Le fichier DebugDoctrineRepositoryTrait.php

Il faut créer le fichier DebugDoctrineRepositoryTrait.php dans le dossier src/Repository puis l'appeler dans le fichier EntityRepository via un use.

src/Repository/DebugDoctrineRepositoryTrait.php
<?php

namespace App\Repository;

trait DebugDoctrineRepositoryTrait
{

    public static function echoSQL($query)
    {
        echo(self::getRawSQL($query).PHP_EOL);
    }

    /*
    public static function dumpSQL($query)
    {
        dump(self::getRawSQL($query));
    }

    public static function ddSQL($query)
    {
        self::dumpSQL($query);
        die;
    }
    */

    public static function getRawSQL($query)
    {
        $attributesToReplace = [];
        preg_match_all('#:([a-zA-Z_0-9]+)#', $query->getDQL(), $attributesToReplace);
        $rawSQL = $query->getSQL();

        foreach ($attributesToReplace[1] as $attrToReplace) {
            foreach ($query->getParameters()->toArray() as $param) {
                if ($attrToReplace === $param->getName()) {
                    //dump("remplacement de : ". $param->getName() . "par " . $param->getValue());
                    if (is_string($param->getValue())) {
                        $rawSQL = preg_replace('#\?#', '"'.$param->getValue().'"', $rawSQL, 1);
                    } elseif(is_numeric($param->getValue())) {
                        $rawSQL = preg_replace('#\?#', ''.$param->getValue().'', $rawSQL, 1);
                    } elseif(is_bool($param->getValue())) {
                        $rawSQL = preg_replace('#\?#', (int) $param->getValue(), $rawSQL, 1);
                    } elseif(is_array($param->getValue())) {
                        $rawSQL = preg_replace('#\?#', '"'.implode('","', $param->getValue()).'"', $rawSQL, 1);
                    } elseif($param->getValue() instanceof \DateTime) {
                        $rawSQL = preg_replace('#\?#', '"'.$param->getValue()->format('Y-m-d H:i:s').'"', $rawSQL, 1);
                    }
                }
            }
        }

        return $rawSQL;
    }
}


4. Exemple d'utilisation

src/Repository/MyEntityRepository.php
<?php
namespace App\Repository;

use Doctrine\ORM\EntityRepository;

/**
 * Class MyEntityRepository
 */
class MyEntityRepository extends EntityRepository
{
    use DebugDoctrineRepositoryTrait;

    /**
     * findOneByColumn
     *
     * @param string $rowId
     *
     * @return MyEntityInterface|null
     *
     * @throws \Doctrine\ORM\NonUniqueResultException
     */
    public function findOneByColumn($rowId)
    {
        $query = $this->createQueryBuilder('o')
            ->where('o.rowId = :rowId')
            ->setParameter('rowId', $rowId)
            ->getQuery()
        
        // Affiche la requête SQL.
        self::echoSQL($query);

        return $query->useQueryCache(true)
            ->useResultCache(false)
            ->setMaxResults(1)
            ->getOneOrNullResult();
    }
}